﻿using SkiaSharp;
using System;
using System.Threading.Tasks;
using ViewFaceCore;
using ViewFaceCore.Configs;
using ViewFaceCore.Core;
using ViewFaceCore.Model;

namespace DoNet.ViewFaceCore.Sdk
{
    /// <summary>
    /// 人脸识别
    /// </summary>
    public class FaceDiscern
    {
        /// <summary>
        /// 获取SKBitmap
        /// </summary>
        /// <param name="filename"></param>
        /// <returns></returns>
        public static SKBitmap GetSKBitmap(string filename)
        {
            return SKBitmap.Decode(filename);
        }

        /// <summary>
        /// 获取FaceImage
        /// </summary>
        /// <param name="filename"></param>
        /// <returns></returns>
        public static FaceImage GetFaceImage(SKBitmap bitmap)
        {
            return bitmap.ToFaceImage();
        }

        #region 同步方法
        /// <summary>
        /// 同步识别 image 中的人脸，并返回人脸的信息。
        /// </summary>
        /// <param name="faceImage">人脸图像信息</param>
        /// <returns></returns>
        public static FaceInfo[] GetFaceInfos(FaceImage faceImage)
        {
            using (FaceDetector faceDetector = new FaceDetector())
            {
                return faceDetector.Detect(faceImage);
            }
        }
        /// <summary>
        /// 同步戴口罩人脸识别
        /// 一般性的，score超过0.5，则认为是检测带上了口罩
        /// </summary>
        /// <param name="faceImage">人脸图像信息</param>
        /// <param name="face">指定的人脸信息</param>
        /// <returns></returns>
        public static PlotMaskResult GetPlotMask(FaceImage faceImage, FaceInfo face)
        {
            using (MaskDetector maskDetector = new MaskDetector())
            {
                return maskDetector.PlotMask(faceImage, face);
            }
        }
        /// <summary>
        /// 同步识别 image 中指定的人脸信息 info 的关键点坐标。
        /// </summary>
        /// <param name="faceImage">人脸图像信息</param>
        /// <param name="face">指定的人脸信息</param>
        /// <returns></returns>
        public static FaceMarkPoint[] GetFaceMarkPoint(FaceImage faceImage, FaceInfo face)
        {
            using (FaceLandmarker faceMark = new FaceLandmarker())
            {
                return faceMark.Mark(faceImage, face);
            }
        }
        /// <summary>
        /// 同步年龄预测
        /// </summary>
        /// <param name="faceImage">人脸图像信息</param>
        /// <param name="points">关键点坐标</param>
        /// <returns></returns>
        public static int GetPredictAge(FaceImage faceImage, FaceMarkPoint[] points)
        {
            using (AgePredictor agePredictor = new AgePredictor())
            {
                return agePredictor.PredictAge(faceImage, points);
            }
        }
        /// <summary>
        /// 同步性别预测
        /// </summary>
        /// <param name="faceImage">人脸图像信息</param>
        /// <param name="points">关键点坐标</param>
        /// <returns></returns>
        public static Gender GetPredictGender(FaceImage faceImage, FaceMarkPoint[] points)
        {
            using (GenderPredictor genderPredictor = new GenderPredictor())
            {
                return genderPredictor.PredictGender(faceImage, points);
            }
        }
        /// <summary>
        /// 同步眼睛状态检测。
        /// 眼睛的左右是相对图片内容而言的左右。
        /// </summary>
        /// <param name="faceImage">人脸图像信息</param>
        /// <param name="points">关键点坐标</param>
        /// <returns></returns>
        public static EyeStateResult GetEyeState(FaceImage faceImage, FaceMarkPoint[] points)
        {
            using (EyeStateDetector eyeStateDetector = new EyeStateDetector())
            {
                return eyeStateDetector.Detect(faceImage, points);
            }
        }
        /// <summary>
        /// 同步人脸质量评估
        /// </summary>
        /// <param name="bitmap">人脸图像信息</param>
        /// <param name="face">指定的人脸信息</param>
        /// <param name="points">关键点坐标</param>
        /// <param name="type">质量评估类型</param>
        /// <returns></returns>
        public static QualityResult GetFaceQuality(SKBitmap bitmap, FaceInfo face, FaceMarkPoint[] points, QualityType type)
        {
            using (FaceQuality faceQuality = new FaceQuality())
            {
                return faceQuality.Detect(bitmap, face, points, type);
            }
        }
        /// <summary>
        /// 同步活体检测器。(单帧图片)
        /// 当 global = false 时， 需要模型：fas_first.csta
        /// 当 global = true 时， 需要模型：fas_second.csta
        /// </summary>
        /// <param name="faceImage">人脸图像信息</param>
        /// <param name="face">指定的人脸信息</param>
        /// <param name="points">关键点坐标</param>
        /// <param name="global">是否开启全局检测模型，默认true</param>
        /// <returns></returns>
        public static AntiSpoofingResult GetAntiSpoofing(FaceImage faceImage, FaceInfo face, FaceMarkPoint[] points, bool global = true)
        {
            FaceAntiSpoofingConfig config = new FaceAntiSpoofingConfig()
            {
                Global = true
            };
            using (FaceAntiSpoofing faceAntiSpoofing = new FaceAntiSpoofing(config))
            {
                return faceAntiSpoofing.AntiSpoofing(faceImage, face, points);
            }
        }
        /// <summary>
        /// 同步活体检测器。(视频帧图片)
        /// 当 global = false 时， 需要模型：fas_first.csta
        /// 当 global = true 时， 需要模型：fas_second.csta
        /// </summary>
        /// <param name="faceImage">人脸图像信息</param>
        /// <param name="face">指定的人脸信息</param>
        /// <param name="points">关键点坐标</param>
        /// <param name="global">是否开启全局检测模型，默认true</param>
        /// <returns></returns>
        public static AntiSpoofingResult GetAntiSpoofingVideo(FaceImage faceImage, FaceInfo face, FaceMarkPoint[] points, bool global = true)
        {
            FaceAntiSpoofingConfig config = new FaceAntiSpoofingConfig()
            {
                Global = true
            };
            using (FaceAntiSpoofing faceAntiSpoofing = new FaceAntiSpoofing(config))
            {
                return faceAntiSpoofing.AntiSpoofingVideo(faceImage, face, points);
            }
        }
        /// <summary>
        /// 同步提取人脸特征值
        /// </summary>
        /// <param name="faceImage">人脸图像信息</param>
        /// <param name="points">关键点坐标</param>
        /// <returns></returns>
        public static float[] GetExtract(FaceImage faceImage, FaceMarkPoint[] points)
        {
            using (FaceRecognizer faceRecognizer = new FaceRecognizer())
            {
                return faceRecognizer.Extract(faceImage, points);
            }
        }
        /// <summary>
        /// 同步识别到的人脸是否为同一人
        /// </summary>
        /// <param name="faceImage0">人脸图像信息0</param>
        /// <param name="points0">关键点坐标0</param>
        /// <param name="faceImage1">人脸图像信息1</param>
        /// <param name="points1">关键点坐标1</param>
        /// <returns></returns>
        public static bool GetIsSelf(FaceImage faceImage0, FaceMarkPoint[] points0, FaceImage faceImage1, FaceMarkPoint[] points1)
        {
            using (FaceRecognizer faceRecognizer = new FaceRecognizer())
            {
                float[] data0 = faceRecognizer.Extract(faceImage0, points0);
                float[] data1 = faceRecognizer.Extract(faceImage1, points1);
                return faceRecognizer.IsSelf(data0, data1);
            }
        }
        #endregion 同步方法

        #region 异步方法
        /// <summary>
        /// 异步识别 image 中的人脸，并返回人脸的信息。
        /// </summary>
        /// <param name="faceImage">人脸图像信息</param>
        /// <returns></returns>
        public static async Task<FaceInfo[]> GetFaceInfosAsync(FaceImage faceImage)
        {
            using (FaceDetector faceDetector = new FaceDetector())
            {
                return await faceDetector.DetectAsync(faceImage);
            }
        }
        /// <summary>
        /// 异步戴口罩人脸识别
        /// 一般性的，score超过0.5，则认为是检测带上了口罩
        /// </summary>
        /// <param name="faceImage">人脸图像信息</param>
        /// <param name="face">指定的人脸信息</param>
        /// <returns></returns>
        public static async Task<PlotMaskResult> GetPlotMaskAsync(FaceImage faceImage, FaceInfo face)
        {
            using (MaskDetector maskDetector = new MaskDetector())
            {
                return await maskDetector.PlotMaskAsync(faceImage, face);
            }
        }
        /// <summary>
        /// 异步识别 image 中指定的人脸信息 info 的关键点坐标。
        /// </summary>
        /// <param name="faceImage">人脸图像信息</param>
        /// <param name="face">指定的人脸信息</param>
        /// <returns></returns>
        public static async Task<FaceMarkPoint[]> GetFaceMarkPointAsync(FaceImage faceImage, FaceInfo face)
        {
            using (FaceLandmarker faceMark = new FaceLandmarker())
            {
                return await faceMark.MarkAsync(faceImage, face);
            }
        }
        /// <summary>
        /// 异步年龄预测
        /// </summary>
        /// <param name="faceImage">人脸图像信息</param>
        /// <param name="points">关键点坐标</param>
        /// <returns></returns>
        public static async Task<int> GetPredictAgeAsync(FaceImage faceImage, FaceMarkPoint[] points)
        {
            using (AgePredictor agePredictor = new AgePredictor())
            {
                return await agePredictor.PredictAgeAsync(faceImage, points);
            }
        }
        /// <summary>
        /// 异步性别预测
        /// </summary>
        /// <param name="faceImage">人脸图像信息</param>
        /// <param name="points">关键点坐标</param>
        /// <returns></returns>
        public static async Task<Gender> GetPredictGenderAsync(FaceImage faceImage, FaceMarkPoint[] points)
        {
            using (GenderPredictor genderPredictor = new GenderPredictor())
            {
                return await genderPredictor.PredictGenderAsync(faceImage, points);
            }
        }
        /// <summary>
        /// 异步眼睛状态检测。
        /// 眼睛的左右是相对图片内容而言的左右。
        /// </summary>
        /// <param name="faceImage">人脸图像信息</param>
        /// <param name="points">关键点坐标</param>
        /// <returns></returns>
        public static async Task<EyeStateResult> GetEyeStateAsync(FaceImage faceImage, FaceMarkPoint[] points)
        {
            using (EyeStateDetector eyeStateDetector = new EyeStateDetector())
            {
                return await eyeStateDetector.DetectAsync(faceImage, points);
            }
        }
        /// <summary>
        /// 异步人脸质量评估
        /// </summary>
        /// <param name="bitmap">人脸图像信息</param>
        /// <param name="face">指定的人脸信息</param>
        /// <param name="points">关键点坐标</param>
        /// <param name="type">质量评估类型</param>
        /// <returns></returns>
        public static async Task<QualityResult> GetGetFaceQualityAsync(SKBitmap bitmap, FaceInfo face, FaceMarkPoint[] points, QualityType type)
        {
            using (FaceQuality faceQuality = new FaceQuality())
            {
                return await faceQuality.DetectAsync(bitmap, face, points, type);
            }
        }
        /// <summary>
        /// 异步活体检测器。(单帧图片)
        /// 当 global = false 时， 需要模型：fas_first.csta
        /// 当 global = true 时， 需要模型：fas_second.csta
        /// </summary>
        /// <param name="faceImage">人脸图像信息</param>
        /// <param name="face">指定的人脸信息</param>
        /// <param name="points">关键点坐标</param>
        /// <param name="global">是否开启全局检测模型，默认true</param>
        /// <returns></returns>
        public static async Task<AntiSpoofingResult> GetAntiSpoofingAsync(FaceImage faceImage, FaceInfo face, FaceMarkPoint[] points, bool global = true)
        {
            FaceAntiSpoofingConfig config = new FaceAntiSpoofingConfig()
            {
                Global = true
            };
            using (FaceAntiSpoofing faceAntiSpoofing = new FaceAntiSpoofing(config))
            {
                return await faceAntiSpoofing.AntiSpoofingAsync(faceImage, face, points);
            }
        }
        /// <summary>
        /// 异步活体检测器。(视频帧图片)
        /// 当 global = false 时， 需要模型：fas_first.csta
        /// 当 global = true 时， 需要模型：fas_second.csta
        /// </summary>
        /// <param name="faceImage">人脸图像信息</param>
        /// <param name="face">指定的人脸信息</param>
        /// <param name="points">关键点坐标</param>
        /// <param name="global">是否开启全局检测模型，默认true</param>
        /// <returns></returns>
        public static async Task<AntiSpoofingResult> GetAntiSpoofingVideoAsync(FaceImage faceImage, FaceInfo face, FaceMarkPoint[] points, bool global = true)
        {
            FaceAntiSpoofingConfig config = new FaceAntiSpoofingConfig()
            {
                Global = true
            };
            using (FaceAntiSpoofing faceAntiSpoofing = new FaceAntiSpoofing(config))
            {
                return await faceAntiSpoofing.AntiSpoofingVideoAsync(faceImage, face, points);
            }
        }
        /// <summary>
        /// 异步提取人脸特征值
        /// </summary>
        /// <param name="faceImage">人脸图像信息</param>
        /// <param name="points">关键点坐标</param>
        /// <returns></returns>
        public static async Task<float[]> GetExtractAsync(FaceImage faceImage, FaceMarkPoint[] points)
        {
            using (FaceRecognizer faceRecognizer = new FaceRecognizer())
            {
                return await faceRecognizer.ExtractAsync(faceImage, points);
            }
        }
        /// <summary>
        /// 异步识别到的人脸是否为同一人
        /// </summary>
        /// <param name="faceImage0">人脸图像信息0</param>
        /// <param name="points0">关键点坐标0</param>
        /// <param name="faceImage1">人脸图像信息1</param>
        /// <param name="points1">关键点坐标1</param>
        /// <returns></returns>
        public static async Task<bool> GetIsSelfAsync(FaceImage faceImage0, FaceMarkPoint[] points0, FaceImage faceImage1, FaceMarkPoint[] points1)
        {
            using (FaceRecognizer faceRecognizer = new FaceRecognizer())
            {
                float[] data0 = await faceRecognizer.ExtractAsync(faceImage0, points0);
                float[] data1 = await faceRecognizer.ExtractAsync(faceImage1, points1);
                return faceRecognizer.IsSelf(data0, data1);
            }
        }
        #endregion 异步方法

        /// <summary>
        /// 
        /// </summary>
        /// <param name="type">质量评估类型：Brightness、Resolution、Clarity、ClarityEx、Integrity、Structure、Pose、PoseEx</param>
        /// <returns></returns>
        /// <exception cref="ArgumentException"></exception>
        public static QualityType GetQualityType(string type)
        {
            switch (type)
            {
                case "Brightness":
                    return QualityType.Brightness;
                case "Resolution":
                    return QualityType.Resolution;
                case "Clarity":
                    return QualityType.Clarity;
                case "ClarityEx":
                    return QualityType.ClarityEx;
                case "Integrity":
                    return QualityType.Integrity;
                case "Structure":
                    return QualityType.Structure;
                case "Pose":
                    return QualityType.Pose;
                case "PoseEx":
                    return QualityType.PoseEx;
                default:
                    throw new ArgumentException($"QualityType异常：{type}");
            }
        }
    }
}
